先前的系列文提過,
可透過 addChild(child) 將可視物件加到容器,並存放在 children 陣列裡
選項1: z-index,隔壁 CSS 就這麼作
選項2: 哪有z-index,都說忘了 CSS,當然是用陣列的順序來調整啊
答案是:都正確
PIXI 裡使用的 zIndex 為小駝峰,與 CSS 屬性的 z-index 不同
此篇接著會以 zIndex 來寫
function createBox(color, w, h, name){
const boxContainer = new PIXI.Container();
boxContainer.name = name;
const box = new PIXI.Graphics();
box.beginFill(color);
box.drawRect(0, 0, 100, 100);
box.endFill();
const infoStyle = new PIXI.TextStyle({
fontSize: 12,
fill: 0xffffff
});
const info = new PIXI.Text(name, infoStyle);
info.x = 5;
info.y = 5;
boxContainer.addChild(box, info);
return boxContainer;
};
app.stage.children.forEach((child, index)=>{
console.log(index, child.name, child.zIndex);
});
準備兩個方塊並用 addChild(child) 加到場景上,
不特別排序深度時,後產生的會放在上頭
const box1 = createBox(0xff0000, 100, 100, "box1");
const box2 = createBox(0xff9900, 100, 100, "box2");
box1.x = 20;
box1.y = 20;
box2.x = 70;
box2.y = 90;
app.stage.addChild(box1);
app.stage.addChild(box2);
沒有無意外的,box2 蓋在 box1 上頭
接著放入一個 box3,放在最下頭
使用 addChildAt(child, 0
) 的方式,直接放在最下方
see also:PIXI.Container#addChildAt
const box3 = createBox(0xff0000, 100, 100, "box3");
box3.x = 20;
box3.y = 220;
app.stage.addChildAt(box3, 0);
box3 會根據指定,放在最下方
此時看到的順序由下往上為 box3 < box1 < box2 (配合陣列順序大的寫在右邊)
這時 children 陣列的順序就變有趣了
box3 應該會在陣列的最後一筆,或是第一筆?
ans: 陣列順序與看到的相同,就是 [box3, box1, box2]
PS. Demo 截圖就是答案了,為方便閱讀沒有另外再截一張
使用 setChildIndex(child, index) 的方式,直接放在最下方
see also:PIXI.Container#setChildIndex
app.stage.setChildIndex(box1, 2)
順利把 box1 挪到上頭,此時的陣列順序與看到的排列順序皆為 box3 < box2 < box1
2
):children 的長度是3,setChildIndex 時,指定的 index 從 0 開始
因此,把 box1 提到最上方的方式
app.stage.setChildIndex(box1, 2
); // 總數 3, 減掉從 0 開始的 1
需注意的是,直接指定childIndex時,指定的index不可超出陣列範圍,
也就是不可小於0
或是大於陣列長度 -1
,否則會跳出錯誤
錯誤訊息為:
addChildI(child) 與 addChildAt(child, index) 都是直接對 children 陣列做操作
在我知道可以用 zIndex 排列前,我都是直接把 children 的順序當作同層級可是物件的 z 順序
可視物件(DisplayObject) 都有 zIndex,同容器的不同可視物件可以有相同的 zIndex
app.stage.children.forEach((child, index)=>{
console.log(index, child.name, child.zIndex);
});
重新一次測試,放上三個,box:
const box1 = createBox(0xff0000, 100, 100, 'box1');
const box2 = createBox(0xff9900, 100, 100, 'box2');
const box3 = createBox(0xff0000, 100, 100, 'box3');
可以看到每個物件的
zIndex 相同
,皆為0
稍早提到 zIndex 可以改變物件順序,
但直接指定 zIndex 不會改變順序:
box2.zIndex = 100;
zIndex 說明:
zIndex
The zIndex of the displayObject. If a container has thesortableChildren
property set totrue
, children will be automatically sorted by zIndex value; a higher value will mean it will be moved towards the end of the array, and thus rendered on top of other displayObjects within the same container.
指定完 zIndex後還再執行 sortChildren() 後,就會依照 zIndex 的設定排序:
box2.zIndex = 100;
app.stage.sortChildren();
有趣的事情發生了
除了會依照 zIndex 排序外,children 裡的陣列順序也改變了!
sortableChildren 為 true 時
會自動依據 zIndex 數值大小
排列,不需另外 sortChildren();
容器元件的 sortableChildren 預設為 false
this.sortableChildren = settings.SORTABLE_CHILDREN;
可從 global 設定更改
更有趣的事情發生了
sortableChildren 設定為 true 且 zIndex 改變時,
並不會立即改變陣列順序,即使隔了 10ms 還是沒更新。
隔了 100ms 後,因為 updateTransform() 執行,深度更新
說明:
sortableChildren
If set to true, the container will sort its children by zIndex value whenupdateTransform() is called
, or manually ifsortChildren() is called
.
不一定會踩到,但滿有趣的
本篇提到各種方法實作與可視物件的繼承有關,後續的內容會提到
本篇補充:
可視範圍的深度基本上是陣列
這邊使用 for 迴圈跑陣列來解釋這個問題:
const arr = ["box1", "box2", "box3", "box4"];
for(let i = 0; i<arr.length; i++){
console.log(i, arr[i]);
if(i === 0){
arr.shift(); // 把第一個元素刪除
}
}
執行迴圈時,陣列長度為 4,會執行 4 次
列出每次執行的情形:
// ["box1", "box2", "box3", "box4"]; // 陣列一開始的樣子
console.log(0, arr[0]); // 第一次,i 為 0; "box1"
arr.shift(); // "box1" 移除; 目前是 ["box2", "box3", "box4"]
console.log(1, arr[1]); // 第一次,i 為 1; "box3"; 此時的 arr[1] 是 "box3"
console.log(2, arr[2]); // 第一次,i 為 2; "box4";
console.log(3, arr[3]); // undefined; i 不是 3
由於在跑第一次的時候,就改變了陣列的順序
在後續的迴圈裡,很容易發生預料外的問題
小結: 不該在迴圈裡調整陣列順序
同理,不該在容器的 children 陣列裡,邊跑迴圈邊更新子物件的深度